package org.jslaughter.main;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.World;

import org.jslaughter.level.Level;
import org.jslaughter.level.Level1;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader;

import org.nvframe.component.physics.util.PhysicsDebugDraw;
import org.nvframe.event.EventService;
import org.nvframe.event.eventtype.UpdateEvent;
import org.nvframe.exception.NVFrameException;
import org.nvframe.factory.EntityFactory;
import org.nvframe.manager.CollisionManager;
import org.nvframe.manager.ConfigManager;
import org.nvframe.manager.EntityManager;
import org.nvframe.manager.InputManager;
import org.nvframe.manager.RegisterManager;
import org.nvframe.manager.RenderManager;
import org.nvframe.manager.ResourceManager;

public class Main extends BasicGame {

	private int iterations = 10;
	private float timestep = 1f / 100f;

	protected World world;
	protected ConfigManager configManager = ConfigManager.getInstance();
	protected RegisterManager registerManager = RegisterManager.getInstance();
	protected InputManager inputManager = InputManager.getInstance();
	
	private List<Level> levels = new ArrayList<Level>();

	public Main() {
		super("jSlaughter - testlevel");
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		// config manager
		configManager.setFunction("debugMode", true);
		configManager.setFunction("engine_vsync", false);
		configManager.setFunction("engine_physics_drawbodies", true);
		configManager.setFunction("engine_entities_showposition", false);
		configManager.setFunction("engine_soundenabled", false);

		// create world for physics and collision
		createWorld();
		
		new PhysicsDebugDraw(world);

		try {
			// load resources
			InputStream inRes = ResourceLoader.getResourceAsStream("level1_resources.xml");
			ResourceManager.getInstance().loadResources(inRes, false);

			// load input commands
			InputStream inInp = ResourceLoader.getResourceAsStream("input.xml");
			inputManager.loadInputKeys(inInp);

			// load entities xml
			InputStream inEnt = ResourceLoader.getResourceAsStream("level1_entities.xml");
			EntityFactory.getInstance().loadEntitiesFromXml(inEnt);
		} catch (NVFrameException e) {
			e.printStackTrace();
		}

		try {
			Level1 level1 = new Level1();
			
			InputStream level1Layout = ResourceLoader.getResourceAsStream("level1_layout.xml");
			level1.createFromXML(level1Layout);
			level1.start();
			
			levels.add(level1);

			// set crosshair to ingame crosshair
			gc.setMouseCursor(ResourceManager.getInstance().getImage("crosshair"), 0, 0);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	public void createWorld() {
		boolean doSleep = true;
		
		// kill gravity for a topdown game
		Vec2 gravity = new Vec2(0.0f, 0.0f);
		
		AABB worldAABB = new AABB();
		worldAABB.lowerBound.set(-100000, -100000);
		worldAABB.upperBound.set(100000, 100000);
		
		world = new World(worldAABB, gravity, doSleep);
		
		// add world to register for later use
		registerManager.setOption("world", world);
		
		// register collisionManager
		CollisionManager collisionManager = CollisionManager.getInstance();
		world.setContactListener(collisionManager);
	}

	public static void main(String[] args) throws SlickException {
		AppGameContainer gc = new AppGameContainer(new Main());

		// engine options
		gc.setVSync(false);
		//gc.setSmoothDeltas(true);
		// gc.setTargetFrameRate(60);
		gc.setDisplayMode(1024, 768, false);
		
		gc.setSoundOn(false);
		
		if(gc.supportsMultiSample())
			gc.setMultiSample(4);
		
		//app.setMouseGrabbed(true);
		
		gc.start();
	}
	
	public void checkFunctionKeys(GameContainer gc) {
		// game options
		Input input = gc.getInput();
		
		// check if a optionkey is pressed
		if (input.isKeyPressed(Input.KEY_F1))
			configManager.toggleActive("debugMode");
		
		if (input.isKeyPressed(Input.KEY_F2)) {
			configManager.toggleActive("engine_vsync");
			gc.setVSync(configManager.getActive("engine_vsync"));
			//gc.setSmoothDeltas(configManager.getActive("engine_vsync"));
		}
		
		if (input.isKeyPressed(Input.KEY_F3))
			configManager.toggleActive("engine_physics_drawbodies");
		
		if (input.isKeyPressed(Input.KEY_F4))
			configManager.toggleActive("engine_entities_showposition");
		
		if (input.isKeyPressed(Input.KEY_F5))
			configManager.toggleActive("engine_soundenabled");
		
		if (input.isKeyPressed(Input.KEY_F12))
			EntityManager.getInstance().printEntities();
	}
	
	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		checkFunctionKeys(gc);
		
		// update physics every timestep (default 1/60)
		world.step(timestep, iterations);

		//EntityManager.update(gc, null, delta);
		EventService.getInstance().fireEvent(new UpdateEvent(gc, delta));
	}

	@Override
	public void render(GameContainer gc, Graphics gr) throws SlickException {
		RenderManager.getInstance().render(gc, null, gr);
	}

}
